home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1995 February: Tool Chest / Dev.CD Feb 95 / Dev.CD Feb 95.toast / Tool Chest / Development Tools & Languages / Dylan Related / Mindy-1.1 (sources only) / mindy-1.1 / interp / debug.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-08-23  |  52.3 KB  |  2,375 lines  |  [TEXT/ttxt]

  1. /**********************************************************************\
  2. *
  3. *  Copyright (c) 1994  Carnegie Mellon University
  4. *  All rights reserved.
  5. *  
  6. *  Use and copying of this software and preparation of derivative
  7. *  works based on this software are permitted, including commercial
  8. *  use, provided that the following conditions are observed:
  9. *  
  10. *  1. This copyright notice must be retained in full on any copies
  11. *     and on appropriate parts of any derivative works.
  12. *  2. Documentation (paper or online) accompanying any system that
  13. *     incorporates this software, or any part of it, must acknowledge
  14. *     the contribution of the Gwydion Project at Carnegie Mellon
  15. *     University.
  16. *  
  17. *  This software is made available "as is".  Neither the authors nor
  18. *  Carnegie Mellon University make any warranty about the software,
  19. *  its performance, or its conformity to any specification.
  20. *  
  21. *  Bug reports, questions, comments, and suggestions should be sent by
  22. *  E-mail to the Internet address "gwydion-bugs@cs.cmu.edu".
  23. *
  24. ***********************************************************************
  25. *
  26. * $Header: debug.c,v 1.34 94/08/22 22:31:08 wlott Exp $
  27. *
  28. * This file implements the debugger.
  29. *
  30. \**********************************************************************/
  31.  
  32. #include <stdio.h>
  33. #include <setjmp.h>
  34. #include <string.h>
  35. #include <sys/param.h>
  36. #include <sys/stat.h>
  37. #ifdef MACH
  38. extern int isatty(int fd);
  39. #endif
  40. #if defined(hpux) || defined(__osf__) || defined(linux) || defined(ultrix)
  41. #define pause buttplug
  42. #include <unistd.h>
  43. #undef pause
  44. #endif
  45. #ifdef sgi
  46. #include <stdlib.h>
  47. #endif
  48.  
  49. #include "mindy.h"
  50. #include "thread.h"
  51. #include "driver.h"
  52. #include "func.h"
  53. #include "module.h"
  54. #include "lexer.h"
  55. #include "parser.h"
  56. #include "str.h"
  57. #include "list.h"
  58. #include "vec.h"
  59. #include "type.h"
  60. #include "sym.h"
  61. #include "num.h"
  62. #include "obj.h"
  63. #include "bool.h"
  64. #include "print.h"
  65. #include "interp.h"
  66. #include "value.h"
  67. #include "error.h"
  68. #include "gc.h"
  69. #include "brkpt.h"
  70. #include "instance.h"
  71. #include "../comp/byteops.h"
  72.  
  73. struct library *CurLibrary = NULL;
  74. struct module *CurModule = NULL;
  75.  
  76. struct frame_info {
  77.     struct frame_info *up;
  78.     struct frame_info *down;
  79.     obj_t *fp;
  80.     obj_t component;
  81.     int pc;
  82.     obj_t source_file;
  83.     obj_t mtime;
  84.     int line;
  85.     obj_t locals;
  86. };
  87.  
  88. static jmp_buf BlowOffCmd;
  89. static struct thread *CurThread = NULL;
  90. static obj_t CurThreadObj = NULL;
  91. static struct frame_info *CurFrame = NULL, *TopFrame = NULL;
  92. static int PrevLine = -1;
  93. static boolean ThreadChanged = FALSE, FrameChanged = FALSE;
  94. static boolean Continue;
  95.  
  96. static obj_t do_eval_func;
  97. static obj_t do_print_func;
  98.  
  99. static struct variable *debugger_eval_var;
  100. static struct variable *debugger_flush_var;
  101. static struct variable *debugger_call_var;
  102. static struct variable *debugger_print_var;
  103. static struct variable *debugger_report_var;
  104. static struct variable *debugger_abort_var;
  105. static struct variable *debugger_restarts_var;
  106. static struct variable *debugger_restart_var;
  107. static struct variable *debugger_return_var;
  108.  
  109.  
  110. /* Frame utilities. */
  111.  
  112. static struct frame_info *make_frame(struct frame_info *up, obj_t *fp,
  113.                      obj_t component, int pc)
  114. {
  115.     struct frame_info *res = malloc(sizeof(*res));
  116.     obj_t debug_info;
  117.     int len, i, n_const;
  118.  
  119.     res->up = up;
  120.     res->down = NULL;
  121.     res->fp = fp;
  122.     res->component = component;
  123.     res->pc = pc;
  124.     res->source_file = obj_False;
  125.     res->mtime = make_fixnum(0);
  126.     res->line = 0;
  127.     res->locals = obj_False;
  128.  
  129.     if (obj_is_fixnum(component))
  130.     return res;
  131.  
  132.     res->source_file = COMPONENT(component)->source_file;
  133.     res->mtime = COMPONENT(component)->mtime;
  134.  
  135.     debug_info = COMPONENT(component)->debug_info;
  136.     if (debug_info == obj_False)
  137.     return res;
  138.  
  139.     n_const = COMPONENT(component)->n_constants;
  140.     pc -= (char *)(&COMPONENT(component)->constant[n_const])-(char *)component;
  141.  
  142.     if (pc < 0)
  143.     return res;
  144.  
  145.     len = SOVEC(debug_info)->length;
  146.     for (i = 0; i < len; i++) {
  147.     obj_t entry = SOVEC(debug_info)->contents[i];
  148.     pc -= fixnum_value(SOVEC(entry)->contents[1]);
  149.     if (pc < 0) {
  150.         res->line = fixnum_value(SOVEC(entry)->contents[0]);
  151.         res->locals = SOVEC(entry)->contents[2];
  152.         break;
  153.     }
  154.     }
  155.  
  156.     return res;
  157. }
  158.  
  159. static struct frame_info *top_frame(struct thread *thread)
  160. {
  161.     if (thread)
  162.     return make_frame(NULL, thread->fp, thread->component, thread->pc);
  163.     else
  164.     return NULL;
  165. }
  166.  
  167. static struct frame_info *frame_down(struct frame_info *frame)
  168. {
  169.     if (frame->down != NULL)
  170.     return frame->down;
  171.     else {
  172.     obj_t *fp = frame->fp;
  173.     obj_t *old_fp = obj_rawptr(fp[-4]);
  174.  
  175.     if (old_fp) {
  176.         frame->down = make_frame(frame, old_fp, fp[-2],
  177.                      fixnum_value(fp[-1]));
  178.         return frame->down;
  179.     }
  180.     else
  181.         return NULL;
  182.     }
  183. }
  184.  
  185. static struct frame_info *frame_up(struct frame_info *frame)
  186. {
  187.     return frame->up;
  188. }
  189.  
  190. static void free_frames(struct frame_info *frame)
  191. {
  192.     struct frame_info *next;
  193.  
  194.     while (frame) {
  195.     next = frame->down;
  196.     free(frame);
  197.     if (frame == CurFrame)
  198.         CurFrame = NULL;
  199.     frame = next;
  200.     }
  201. }
  202.  
  203. static void scav_frames(struct frame_info *frame)
  204. {
  205.     while (frame != NULL) {
  206.     scavenge(&frame->component);
  207.     scavenge(&frame->source_file);
  208.     scavenge(&frame->mtime);
  209.     scavenge(&frame->locals);
  210.     frame = frame->down;
  211.     }
  212. }
  213.  
  214. static void print_frame(struct frame_info *frame, boolean print_line)
  215. {
  216.     obj_t *ptr = obj_rawptr(frame->fp[-3]);
  217.     obj_t *end = frame->fp - 4;
  218.  
  219.     printf("fp 0x%08lx: ", (unsigned long)frame->fp);
  220.     prin1(function_debug_name_or_self(*ptr++));
  221.     putchar('(');
  222.     if (ptr < end) {
  223.     while (1) {
  224.         prin1(*ptr++);
  225.         if (ptr >= end)
  226.         break;
  227.         printf(", ");
  228.     }
  229.     }
  230.     if (frame->source_file == obj_False || !print_line)
  231.     printf(")\n");
  232.     else {
  233.     printf(") [%s", string_chars(frame->source_file));
  234.     if (frame->line == 0)
  235.         printf("]\n");
  236.     else
  237.         printf(", line %d]\n", frame->line);
  238.     }
  239. }
  240.  
  241. static void set_frame(struct frame_info *frame)
  242. {
  243.     if (CurFrame == NULL || frame == NULL || CurFrame->fp != frame->fp) {
  244.     FrameChanged = TRUE;
  245.     PrevLine = -1;
  246.     }
  247.  
  248.     CurFrame = frame;
  249. }
  250.  
  251.  
  252.  
  253. /* Thread utilities. */
  254.  
  255. static void set_thread(struct thread *thread)
  256. {
  257.     CurThread = thread;
  258.     if (thread != NULL)
  259.     CurThreadObj = thread->thread_obj;
  260.     else
  261.     CurThreadObj = NULL;
  262.     ThreadChanged = TRUE;
  263.     free_frames(TopFrame);
  264.     TopFrame = top_frame(thread);
  265.     set_frame(TopFrame);
  266. }
  267.  
  268. static void print_thread(struct thread *thread)
  269. {
  270.     static char *status_chars = {"RSDBW"};
  271.     printf("[%d] %c ", thread->id, status_chars[(int)thread->status]);
  272.     if (thread->suspend_count != 0)
  273.     printf("%d ", thread->suspend_count);
  274.     else
  275.     printf("  ");
  276.     if (THREAD(thread->thread_obj)->debug_name != obj_False)
  277.     print(THREAD(thread->thread_obj)->debug_name);
  278.     else
  279.     putchar('\n');
  280. }
  281.  
  282. static void suspend_other_threads(struct thread *thread)
  283. {
  284.     struct thread_list *threads;
  285.  
  286.     for (threads = all_threads(); threads != NULL; threads = threads->next)
  287.     if (threads->thread != thread)
  288.         thread_suspend(threads->thread);
  289. }
  290.  
  291. static void restart_other_threads(struct thread *thread)
  292. {
  293.     struct thread_list *threads;
  294.  
  295.     for (threads = all_threads(); threads != NULL; threads = threads->next)
  296.     if (threads->thread != thread)
  297.         thread_restart(threads->thread);
  298. }
  299.  
  300. static void kill_me(struct thread *thread, obj_t *vals)
  301. {
  302.     thread_kill(thread);
  303.     restart_other_threads(NULL);
  304.     set_thread(NULL);
  305.     pause(pause_DebuggerCommandFinished);
  306. }
  307.  
  308. static void debugger_cmd_finished(struct thread *thread, obj_t *vals)
  309. {
  310.     thread->sp = vals;
  311.     thread_pop_escape(thread);
  312.     restart_other_threads(thread);
  313.     pause(pause_DebuggerCommandFinished);
  314. }
  315.  
  316. static void validate_thread_and_frame()
  317. {
  318.     if (CurThread != NULL) {
  319.     if (THREAD(CurThreadObj)->thread == NULL) {
  320.         printf("Current thread no longer exists.\n");
  321.         set_thread(NULL);
  322.         ThreadChanged = FALSE;
  323.         FrameChanged = FALSE;
  324.         return;
  325.     }
  326.  
  327.     if (TopFrame == NULL) {
  328.         if (CurThread->fp != NULL) {
  329.         TopFrame = top_frame(CurThread);
  330.         set_frame(TopFrame);
  331.         }
  332.     }
  333.     else {
  334.         if (CurThread->fp != TopFrame->fp
  335.           || CurThread->component != TopFrame->component
  336.           || CurThread->pc != TopFrame->pc) {
  337.         struct frame_info *old_top = TopFrame;
  338.         TopFrame = top_frame(CurThread);
  339.         set_frame(TopFrame);
  340.         free_frames(old_top);
  341.         }
  342.     }
  343.     }
  344. }
  345.  
  346.  
  347. /* Source code stuff. */
  348.  
  349. static obj_t cur_source_file = NULL;
  350. static time_t cur_mtime = 0;
  351. static FILE *cur_source_stream = NULL;
  352. static long *line_offsets = NULL;
  353. static int lines_alloced = 0;
  354. static int lines_found = 0;
  355. static char **source_directories = NULL;
  356.  
  357. static FILE *find_source_line(obj_t file, obj_t mtime, int line)
  358. {
  359.     int c;
  360.  
  361.     if (file == obj_False)
  362.     return NULL;
  363.  
  364.     if (file != cur_source_file) {
  365.     char *name = string_chars(file);
  366.  
  367.     if (cur_source_stream != NULL) {
  368.         fclose(cur_source_stream);
  369.         cur_source_stream = NULL;
  370.     }
  371.     
  372.     if (source_directories == NULL || name[0] == '/')
  373.         cur_source_stream = fopen(name, "r");
  374.     else
  375.         cur_source_stream = NULL;
  376.  
  377.     cur_source_file = file;
  378.     cur_mtime = 0;
  379.     if (line_offsets == NULL) {
  380.         lines_alloced = 1000;
  381.         line_offsets = malloc(sizeof(long) * lines_alloced);
  382.         line_offsets[0] = 0;
  383.         line_offsets[1] = 0;
  384.     }
  385.     lines_found = 1;
  386.     }
  387.  
  388.     if (cur_source_stream == NULL)
  389.     return NULL;
  390.  
  391.     if (cur_mtime == 0) {
  392.     struct stat buf;
  393.  
  394.     fstat(fileno(cur_source_stream), &buf);
  395.  
  396.     cur_mtime = buf.st_mtime;
  397.     }
  398.  
  399.     if (cur_mtime != fixnum_value(mtime))
  400.     printf("\nWarning: %s has changed", string_chars(file));
  401.  
  402.     if (line > lines_found) {
  403.     fseek(cur_source_stream, line_offsets[lines_found], 0);
  404.     while ((c = getc(cur_source_stream)) != EOF) {
  405.         if (c == '\n') {
  406.         lines_found++;
  407.         if (lines_found >= lines_alloced) {
  408.             lines_alloced *= 2;
  409.             line_offsets = realloc(line_offsets,
  410.                        sizeof(long) * lines_alloced);
  411.         }
  412.         line_offsets[lines_found] = ftell(cur_source_stream);
  413.         if (lines_found == line)
  414.             break;
  415.         }
  416.     }
  417.     }
  418.     else
  419.     fseek(cur_source_stream, line_offsets[line], 0);
  420.  
  421.     return cur_source_stream;
  422. }
  423.  
  424.  
  425.  
  426. /* Stuff to explain the reason why we dropped into the debugger. */
  427.  
  428. static void explain_condition(struct thread *thread, obj_t condition)
  429. {
  430.     if (instancep(condition, obj_SimpleObjectVectorClass)) {
  431.     char *fmt = string_chars(SOVEC(condition)->contents[0]);
  432.  
  433.     putchar('\n');
  434.     vformat(fmt, SOVEC(condition)->contents+1);
  435.     printf("\n\n");
  436.     }
  437.     else if (debugger_report_var == NULL
  438.          || debugger_report_var->value == obj_Unbound) {
  439.     printf("\ninvoke-debugger called from dylan.  Condition = ");
  440.     print(condition);
  441.     putchar('\n');
  442.     }
  443.     else {
  444.     thread_push_escape(thread);
  445.     set_c_continuation(thread, debugger_cmd_finished);
  446.  
  447.     suspend_other_threads(thread);
  448.  
  449.     *thread->sp++ = debugger_report_var->value;
  450.     *thread->sp++ = condition;
  451.     thread_restart(thread);
  452.     Continue = TRUE;
  453.     }
  454. }
  455.  
  456. static void explain_debugger_invocation(void)
  457. {
  458.     struct thread *thread = thread_current();
  459.  
  460.     set_thread(thread);
  461.  
  462.     if (thread == NULL) {
  463.     printf("Debugger explicitly invoked, but no current thread?\n");
  464.     ThreadChanged = FALSE;
  465.     FrameChanged = FALSE;
  466.     return;
  467.     }
  468.  
  469.     if (thread->status != status_Debuggered) {
  470.     printf("Debugger explicitly invoked, but not by current thread?\n");
  471.     return;
  472.     }
  473.  
  474.     explain_condition(thread, thread->datum);
  475. }
  476.  
  477. static void explain_reason(enum pause_reason reason)
  478. {
  479.     switch (reason) {
  480.       case pause_NoReason:
  481.       case pause_PickNewThread:
  482.       case pause_DebuggerCommandFinished:
  483.     validate_thread_and_frame();
  484.     break;
  485.       case pause_NothingToRun:
  486.     printf("All threads exited.\n");
  487.     set_thread(NULL);
  488.     ThreadChanged = FALSE;
  489.     FrameChanged = FALSE;
  490.     break;
  491.       case pause_Interrupted:
  492.     printf("Interrupted\n");
  493.     set_thread(thread_current());
  494.     break;
  495.       case pause_DebuggerInvoked:
  496.     explain_debugger_invocation();
  497.     break;
  498.       case pause_HitBreakpoint:
  499.     printf("Breakpoint\n");
  500.     set_thread(thread_current());
  501.     break;
  502.     }
  503. }
  504.  
  505.  
  506. /* Command tables. */
  507.  
  508. struct cmd_entry {
  509.     char *cmd;
  510.     char *help;
  511.     void (*fn)(void);
  512. };
  513.  
  514. static struct cmd_entry *find_cmd(struct cmd_entry *table, char *what)
  515. {
  516.     struct cmd_entry *match = NULL;
  517.  
  518.     while (table->cmd) {
  519.     if (strncmp(table->cmd, yytext, yyleng) == 0) {
  520.         if (strlen(table->cmd) == yyleng)
  521.         return table;
  522.         else if (match) {
  523.         printf("ambiguous %s, could be either ``%s'' or ``%s''\n",
  524.                what, match->cmd, table->cmd);
  525.         return NULL;
  526.         }
  527.         else
  528.         match = table;
  529.     }
  530.     table++;
  531.     }
  532.  
  533.     if (match == NULL)
  534.     printf("unknown %s\n", what);
  535.  
  536.     return match;
  537. }
  538.  
  539.  
  540. /* Generic Commands */
  541.  
  542. static void quit_cmd(void)
  543. {
  544.     exit(0);
  545. }
  546.  
  547. static void continue_cmd(void)
  548. {
  549.     struct thread_list *threads;
  550.  
  551.     for (threads = all_threads(); threads != NULL; threads = threads->next) {
  552.     enum thread_status status = threads->thread->status;
  553.  
  554.     if (status == status_Running || status == status_Waiting) {
  555.         Continue = TRUE;
  556.         return;
  557.     }
  558.     }
  559.  
  560.     printf("No threads are potentially runnable.\n");
  561. }
  562.  
  563. static void tron_cmd(void)
  564. {
  565.     extern boolean Tracing;
  566.     Tracing = TRUE;
  567. }
  568.  
  569. static void troff_cmd(void)
  570. {
  571.     extern boolean Tracing;
  572.     Tracing = FALSE;
  573. }
  574.  
  575. static void gc_cmd(void)
  576. {
  577.     collect_garbage();
  578. }
  579.  
  580. static void error_cmd(void)
  581. {
  582.     if (CurThread == NULL)
  583.     printf("No current thread.\n");
  584.     else if (CurThread->status != status_Debuggered)
  585.     printf("The current thread did not stop due to an error.\n");
  586.     else
  587.     explain_condition(CurThread, CurThread->datum);
  588. }
  589.  
  590. /* help_cmd is defined later, because it needs to */
  591. /* reference the cmd table. */
  592. static void help_cmd(void);
  593.  
  594.  
  595. /* Frame manipulation commands. */
  596.  
  597. static void down_cmd(void)
  598. {
  599.     if (CurThread == NULL)
  600.     printf("No current thread.\n");
  601.     else if (CurFrame == NULL)
  602.     printf("The current thread has nothing on the stack.\n");
  603.     else {
  604.     struct frame_info *down = frame_down(CurFrame);
  605.  
  606.     if (down != NULL)
  607.         set_frame(down);
  608.     else
  609.         printf("Already at the bottom of the stack.\n");
  610.     }
  611. }
  612.  
  613. static void up_cmd(void)
  614. {
  615.     if (CurThread == NULL)
  616.     printf("No current thread.\n");
  617.     else if (CurFrame == NULL)
  618.     printf("The current thread has nothing on the stack.\n");
  619.     else {
  620.     struct frame_info *up = frame_up(CurFrame);
  621.  
  622.     if (up != NULL)
  623.         set_frame(up);
  624.     else
  625.         printf("Already at the top of the stack.\n");
  626.     }
  627. }
  628.  
  629. static void frame_cmd(void)
  630. {
  631.     if (CurThread == NULL)
  632.     printf("No current thread.\n");
  633.     else if (TopFrame == NULL)
  634.     printf("The current thread has nothing on the stack.\n");
  635.     else {
  636.     int tok = yylex();
  637.  
  638.     if (tok == tok_EOF)
  639.         FrameChanged = TRUE;
  640.     else if (tok != tok_LITERAL || !obj_is_fixnum(yylval))
  641.         printf("Bogus frame number, should be an integer.\n");
  642.     else {
  643.         int num = fixnum_value(yylval);
  644.  
  645.         if (num < 0)
  646.         printf("Bogus frame number, should be >= 0.\n");
  647.         else {
  648.         struct frame_info *frame = TopFrame;
  649.         int i;
  650.  
  651.         for (i = 0; frame != NULL && i < num; i++)
  652.             frame = frame_down(frame);
  653.  
  654.         if (frame == NULL)
  655.             printf("Frame number too large, should be < %d.\n", i);
  656.         else {
  657.             set_frame(NULL);
  658.             set_frame(frame);
  659.         }
  660.         }
  661.     }
  662.     }
  663. }
  664.  
  665. static boolean backtrace_punted;
  666.  
  667. static void punt_backtrace(void)
  668. {
  669.     backtrace_punted = TRUE;
  670. }
  671.  
  672. static void backtrace_cmd(void)
  673. {
  674.     if (CurThread == NULL)
  675.     printf("No current thread.\n");
  676.     else {
  677.     struct frame_info *frame;
  678.     
  679.     backtrace_punted = FALSE;
  680.     set_interrupt_handler(punt_backtrace);
  681.  
  682.     for (frame = TopFrame; frame != NULL; frame = frame_down(frame)) {
  683.         if (backtrace_punted) {
  684.         printf("interrupted\n");
  685.         break;
  686.         }
  687.         print_frame(frame, TRUE);
  688.     }
  689.  
  690.     clear_interrupt_handler();
  691.     }
  692. }
  693.  
  694.  
  695. /* Library/module/variable manipulation commands. */
  696.  
  697. static void library_cmd(void)
  698. {
  699.     struct library *lib;
  700.  
  701.     switch (yylex()) {
  702.       case tok_EOF:
  703.     list_libraries();
  704.     putchar('\n');
  705.     if (CurLibrary) {
  706.         printf("Current library is ");
  707.         print(library_name(CurLibrary));
  708.     }
  709.     else
  710.         printf("No library currently selected\n");
  711.     break;
  712.       case tok_SYMBOL:
  713.     lib = find_library(yylval, FALSE);
  714.     if (lib) {
  715.         CurLibrary = lib;
  716.         CurModule = find_module(lib, symbol("Dylan-User"), FALSE, FALSE);
  717.     }
  718.     else {
  719.         printf("No library named ");
  720.         print(yylval);
  721.     }
  722.     break;
  723.       default:
  724.     printf("Syntax error.\n");
  725.     break;
  726.     }
  727. }
  728.  
  729. static void module_cmd(void)
  730. {
  731.     struct module *module;
  732.  
  733.     if (CurLibrary == NULL) {
  734.     printf("No library currently selected.\n");
  735.     return;
  736.     }
  737.  
  738.     switch (yylex()) {
  739.       case tok_EOF:
  740.     list_modules(CurLibrary);
  741.     putchar('\n');
  742.     if (CurModule) {
  743.         printf("The current module is ");
  744.         print(module_name(CurModule));
  745.     }
  746.     else
  747.         printf("No module currently selected.\n");
  748.     break;
  749.       case tok_SYMBOL:
  750.     module = find_module(CurLibrary, yylval, FALSE, FALSE);
  751.     if (module)
  752.         CurModule = module;
  753.     else {
  754.         printf("No module named ");
  755.         print(yylval);
  756.     }
  757.     break;
  758.       default:
  759.     printf("Syntax error.\n");
  760.     break;
  761.     }
  762. }
  763.  
  764.  
  765. /* Locals command. */
  766.  
  767. static void locals_cmd()
  768. {
  769.     obj_t locals;
  770.  
  771.     if (CurFrame == NULL) {
  772.     printf("No current frame.\n");
  773.     return;
  774.     }
  775.  
  776.     locals = CurFrame->locals;
  777.     if (locals == obj_False) {
  778.     printf("No debug info for this frame.\n");
  779.     return;
  780.     }
  781.  
  782.     while (locals != obj_Nil) {
  783.     obj_t vec = HEAD(locals);
  784.     int len = SOVEC(vec)->length;
  785.     int i;
  786.  
  787.     for (i = 0; i < len; i++) {
  788.         obj_t entry = SOVEC(vec)->contents[i];
  789.         obj_t symbol = SOVEC(entry)->contents[0];
  790.         int loc_info = fixnum_value(SOVEC(entry)->contents[1]);
  791.         boolean indirect = loc_info & 2;
  792.         boolean argument = loc_info & 1;
  793.         int offset = loc_info >> 2;
  794.         obj_t value;
  795.  
  796.         if (argument)
  797.         value = CurFrame->fp[-offset-5];
  798.         else
  799.         value = CurFrame->fp[offset];
  800.         if (indirect)
  801.         value = value_cell_ref(value);
  802.  
  803.         prin1(symbol);
  804.         printf(": ");
  805.         print(value);
  806.     }
  807.  
  808.     locals = TAIL(locals);
  809.     }
  810. }
  811.  
  812.  
  813.  
  814. /* Flush command. */
  815.  
  816. static void flush_cmd(void)
  817. {
  818.     struct thread *thread;
  819.  
  820.     if (debugger_flush_var == NULL
  821.       || debugger_flush_var->value == obj_Unbound) {
  822.     printf("debugger-flush undefined.\n");
  823.     return;
  824.     }
  825.  
  826.     if ((thread = CurThread) == NULL) {
  827.     thread = thread_create(make_string("debugger flush cmd"));
  828.     set_c_continuation(thread, kill_me);
  829.     }
  830.  
  831.     thread_push_escape(thread);
  832.     set_c_continuation(thread, debugger_cmd_finished);
  833.     
  834.     suspend_other_threads(thread);
  835.     
  836.     *thread->sp++ = debugger_flush_var->value;
  837.     thread_restart(thread);
  838.     Continue = TRUE;
  839. }
  840.  
  841.  
  842.  
  843. /* print command. */
  844.  
  845. static void eval_vars(obj_t expr, boolean *okay, boolean *simple)
  846. {
  847.     obj_t kind = HEAD(expr);
  848.  
  849.     if (kind == symbol("literal")) {
  850.     /* Don't have to do anything for literals. */
  851.     }
  852.     else if (kind == symbol("variable")) {
  853.     /* Variable reference. */
  854.     obj_t name = TAIL(expr);
  855.     if (CurFrame != NULL && CurFrame->locals != obj_False) {
  856.         obj_t list = CurFrame->locals;
  857.         while (list != obj_Nil) {
  858.         obj_t vec = HEAD(list);
  859.         int len = SOVEC(vec)->length;
  860.         int i;
  861.         for (i = 0; i < len; i++) {
  862.             obj_t entry = SOVEC(vec)->contents[i];
  863.             if (SOVEC(entry)->contents[0] == name) {
  864.             int loc_info = fixnum_value(SOVEC(entry)->contents[1]);
  865.             boolean indirect = loc_info & 2;
  866.             boolean argument = loc_info & 1;
  867.             int offset = loc_info >> 2;
  868.             obj_t value;
  869.  
  870.             if (argument)
  871.                 value = CurFrame->fp[-offset-5];
  872.             else
  873.                 value = CurFrame->fp[offset];
  874.             if (indirect)
  875.                 value = value_cell_ref(value);
  876.             HEAD(expr) = symbol("literal");
  877.             TAIL(expr) = value;
  878.             return;
  879.             }
  880.         }
  881.         list = TAIL(list);
  882.         }
  883.     }
  884.     if (CurModule == NULL) {
  885.         if (*okay) {
  886.         printf("No module currently selected\n");
  887.         *okay = FALSE;
  888.         }
  889.     }
  890.     else {
  891.         struct variable *var = find_variable(CurModule, name,
  892.                          FALSE, FALSE);
  893.         if (var == NULL) {
  894.         printf("no variable named %s in module %s\n",
  895.                sym_name(name),
  896.                sym_name(module_name(CurModule)));
  897.         *okay = FALSE;
  898.         }
  899.         else {
  900.         obj_t value = var->value;
  901.         if (value == obj_Unbound) {
  902.             printf("variable %s in module %s is unbound\n",
  903.                sym_name(name), sym_name(module_name(CurModule)));
  904.             *okay = FALSE;
  905.         }
  906.         else {
  907.             HEAD(expr) = symbol("literal");
  908.             TAIL(expr) = value;
  909.         }
  910.         }
  911.     }
  912.     }
  913.     else if (kind == symbol("debug-var"))
  914.     *simple = FALSE;
  915.     else if (kind == symbol("arg")) {
  916.     if (CurFrame == NULL)  {
  917.         printf("No current frame.\n");
  918.         *okay = FALSE;
  919.     }
  920.     else {
  921.         obj_t *fp = CurFrame->fp;
  922.         obj_t *args = ((obj_t *)obj_rawptr(fp[-3])) + 1;
  923.         int nargs = fp - args - 4;
  924.         int arg = fixnum_value(TAIL(expr));
  925.  
  926.         if (arg >= nargs) {
  927.         printf("%d too large -- Only %d argument%s\n", arg, nargs,
  928.                nargs == 1 ? "" : "s");
  929.         *okay = FALSE;
  930.         }
  931.         else {
  932.         HEAD(expr) = symbol("literal");
  933.         TAIL(expr) = args[arg];
  934.         }
  935.     }
  936.     }
  937.     else if (kind == symbol("funcall")) {
  938.     obj_t args;
  939.  
  940.     for (args = TAIL(expr); args != obj_Nil; args = TAIL(args))
  941.         eval_vars(HEAD(args), okay, simple);
  942.     
  943.     *simple = FALSE;
  944.     }
  945.     else
  946.     lose("Parser returned something strange.");
  947. }
  948.  
  949. static void do_eval(struct thread *thread, obj_t args, int nargs);
  950. static void do_more_prints(struct thread *thread, obj_t exprs);
  951.  
  952. static void eval_return(struct thread *thread, obj_t *vals)
  953. {
  954.     do_return(thread, pop_linkage(thread), vals);
  955. }
  956.  
  957. static void continue_eval(struct thread *thread, obj_t *vals)
  958. {
  959.     obj_t args = vals[-2];
  960.     int nargs = fixnum_value(vals[-1]);
  961.  
  962.     vals[-2] = vals[0];
  963.     thread->sp = vals - 1;
  964.  
  965.     do_eval(thread, args, nargs);
  966. }
  967.  
  968. static void do_eval(struct thread *thread, obj_t args, int nargs)
  969. {
  970.     while (args != obj_Nil) {
  971.     obj_t arg = HEAD(args);
  972.     obj_t kind = HEAD(arg);
  973.  
  974.     if (kind == symbol("literal")) {
  975.         *thread->sp++ = TAIL(arg);
  976.         nargs++;
  977.     }
  978.     else if (kind == symbol("funcall")) {
  979.         *thread->sp++ = TAIL(args);
  980.         *thread->sp++ = make_fixnum(nargs+1);
  981.         *thread->sp++ = do_eval_func;
  982.         *thread->sp++ = TAIL(arg);
  983.         set_c_continuation(thread, continue_eval);
  984.         invoke(thread, 1);
  985.         return;
  986.     }
  987.     else
  988.         lose("Print command found a strange expression.");
  989.     args = TAIL(args);
  990.     }
  991.     /* One of the ``args'' is the function. */
  992.     check_type(thread->sp[-nargs], obj_FunctionClass);
  993.     set_c_continuation(thread, eval_return);
  994.     invoke(thread, nargs-1);
  995. }
  996.  
  997. static void do_eval_start(struct thread *thread, int nargs)
  998. {
  999.     obj_t *args = thread->sp - 1;
  1000.     obj_t eval_args = args[0];
  1001.  
  1002.     assert(nargs == 1);
  1003.  
  1004.     push_linkage(thread, args);
  1005.     do_eval(thread, eval_args, 0);
  1006. }
  1007.  
  1008. static void do_print(struct thread *thread, obj_t *vals)
  1009. {
  1010.     obj_t *old_sp = vals - 1;
  1011.     obj_t exprs = *old_sp;
  1012.  
  1013.     if (vals == thread->sp)
  1014.     printf("[returned 0 values]\n");
  1015.     else {
  1016.     while (1) {
  1017.         prin1(*vals++);
  1018.         if (vals < thread->sp)
  1019.         printf(", ");
  1020.         else {
  1021.         putchar('\n');
  1022.         break;
  1023.         }
  1024.     }
  1025.     }
  1026.  
  1027.     thread->sp = old_sp;
  1028.  
  1029.     do_more_prints(thread, exprs);
  1030. }
  1031.  
  1032. static void do_more_prints(struct thread *thread, obj_t exprs)
  1033. {
  1034.     while (exprs != obj_Nil) {
  1035.     obj_t expr = HEAD(exprs);
  1036.     obj_t kind = HEAD(expr);
  1037.  
  1038.     if (kind == symbol("literal")) {
  1039.         print(TAIL(expr));
  1040.     }
  1041.     else if (kind == symbol("funcall")) {
  1042.         *thread->sp++ = TAIL(exprs);
  1043.         *thread->sp++ = do_eval_func;
  1044.         *thread->sp++ = TAIL(expr);
  1045.         set_c_continuation(thread, do_print);
  1046.         invoke(thread, 1);
  1047.         return;
  1048.     }
  1049.     else
  1050.         lose("Print command found a strange expression.");
  1051.     }
  1052.  
  1053.     {
  1054.     obj_t *old_sp = pop_linkage(thread);
  1055.     thread->sp = old_sp;
  1056.     do_return(thread, old_sp, old_sp);
  1057.     }
  1058. }
  1059.  
  1060. static void do_print_start(struct thread *thread, int nargs)
  1061. {
  1062.     obj_t *args = thread->sp - 1;
  1063.  
  1064.     assert(nargs == 1);
  1065.  
  1066.     push_linkage(thread, args);
  1067.     do_more_prints(thread, args[0]);
  1068. }
  1069.  
  1070. static void call_or_print(struct variable *var)
  1071. {
  1072.     obj_t exprs = parse_exprs();
  1073.     boolean okay = TRUE;
  1074.     boolean simple = TRUE;
  1075.     obj_t expr;
  1076.     struct thread *thread;
  1077.  
  1078.     if (exprs == obj_False) {
  1079.     printf("Invalid expression.\n");
  1080.     return;
  1081.     }
  1082.     if (exprs == obj_Nil) {
  1083.     printf("No expression.\n");
  1084.     return;
  1085.     }
  1086.  
  1087.     for (expr = exprs; expr != obj_Nil; expr = TAIL(expr))
  1088.     eval_vars(HEAD(expr), &okay, &simple);
  1089.  
  1090.     if (!okay)
  1091.     return;
  1092.  
  1093.     if (simple && (var == NULL || var->value == obj_Unbound)) {
  1094.     for (expr = exprs; expr != obj_Nil; expr = TAIL(expr))
  1095.         print(TAIL(HEAD(expr)));
  1096.     return;
  1097.     }
  1098.  
  1099.     if (CurThread == NULL) {
  1100.     thread = thread_create(var ? var->name : obj_False);
  1101.     set_c_continuation(thread, kill_me);
  1102.     }
  1103.     else {
  1104.     thread = CurThread;
  1105.     thread_push_escape(thread);
  1106.     set_c_continuation(thread, debugger_cmd_finished);
  1107.     }
  1108.  
  1109.     suspend_other_threads(thread);
  1110.  
  1111.     if (var == NULL || var->value == obj_Unbound)
  1112.     *thread->sp++ = do_print_func;
  1113.     else
  1114.     *thread->sp++ = var->value;
  1115.     *thread->sp++ = exprs;
  1116.  
  1117.     thread_restart(thread);
  1118.     Continue = TRUE;
  1119. }
  1120.  
  1121.  
  1122. static void call_cmd(void)
  1123. {
  1124.     call_or_print(debugger_call_var);
  1125. }
  1126.  
  1127. static void print_cmd(void)
  1128. {
  1129.     call_or_print(debugger_print_var);
  1130. }
  1131.  
  1132.  
  1133. /* Restart commands. */
  1134.  
  1135. static void abort_cmd(void)
  1136. {
  1137.     struct thread *thread;
  1138.  
  1139.     if (debugger_abort_var == NULL
  1140.       || debugger_abort_var->value == obj_Unbound) {
  1141.     printf("debugger-abort undefined.\n");
  1142.     return;
  1143.     }
  1144.  
  1145.     if ((thread = CurThread) == NULL) {
  1146.     printf("No current thread.\n");
  1147.     return;
  1148.     }
  1149.  
  1150.     thread_push_escape(thread);
  1151.     set_c_continuation(thread, debugger_cmd_finished);
  1152.     
  1153.     suspend_other_threads(thread);
  1154.     
  1155.     *thread->sp++ = debugger_abort_var->value;
  1156.     thread_restart(thread);
  1157.     Continue = TRUE;
  1158. }
  1159.  
  1160. static void describe_restarts(void)
  1161. {
  1162.     obj_t cond;
  1163.     struct thread *thread;
  1164.  
  1165.     if (debugger_restarts_var == NULL
  1166.       || debugger_restarts_var->value == obj_Unbound) {
  1167.     printf("debugger-describe-restarts undefined.\n");
  1168.     return;
  1169.     }
  1170.  
  1171.     if ((thread = CurThread) == NULL) {
  1172.     printf("No current thread.\n");
  1173.     return;
  1174.     }
  1175.  
  1176.     if (thread->status == status_Debuggered)
  1177.     cond = thread->datum;
  1178.     else
  1179.     cond = obj_False;
  1180.  
  1181.     thread_push_escape(thread);
  1182.     set_c_continuation(thread, debugger_cmd_finished);
  1183.     
  1184.     suspend_other_threads(thread);
  1185.     
  1186.     *thread->sp++ = debugger_restarts_var->value;
  1187.     *thread->sp++ = cond;
  1188.     thread_restart(thread);
  1189.     Continue = TRUE;
  1190. }
  1191.  
  1192. static void maybe_return(struct thread *thread, obj_t *vals)
  1193. {
  1194.     if (vals[0] == obj_False) {
  1195.     thread->sp = vals;
  1196.     thread_pop_escape(thread);
  1197.     thread->sp--;
  1198.     pause(pause_DebuggerCommandFinished);
  1199.     }
  1200.     else {
  1201.     obj_t value_vec = vals[1];
  1202.     int len = SOVEC(value_vec)->length;
  1203.     int i;
  1204.     obj_t *old_sp;
  1205.     obj_t keep_going;
  1206.  
  1207.     thread->sp = vals;
  1208.     thread_pop_escape(thread);
  1209.  
  1210.     keep_going = *--thread->sp;
  1211.  
  1212.     thread_buggered(thread);
  1213.  
  1214.     old_sp = pop_linkage(thread);
  1215.  
  1216.     thread->sp = old_sp + len;
  1217.  
  1218.     for (i = 0; i < len; i++)
  1219.         old_sp[i] = SOVEC(value_vec)->contents[i];
  1220.  
  1221.     restart_other_threads(thread);
  1222.  
  1223.     if (keep_going != obj_False)
  1224.         do_return(thread, old_sp, old_sp);
  1225.     else {
  1226.         do_return_setup(thread, old_sp, old_sp);
  1227.         pause(pause_DebuggerCommandFinished);
  1228.     }
  1229.     }
  1230. }
  1231.  
  1232. static void do_restart(obj_t restart)
  1233. {
  1234.     obj_t cond;
  1235.     struct thread *thread;
  1236.  
  1237.     if (debugger_restart_var == NULL
  1238.       || debugger_restart_var->value == obj_Unbound) {
  1239.     printf("debugger-restart undefined.\n");
  1240.     return;
  1241.     }
  1242.  
  1243.     if ((thread = CurThread) == NULL) {
  1244.     printf("No current thread.\n");
  1245.     return;
  1246.     }
  1247.  
  1248.     if (thread->status == status_Debuggered)
  1249.     cond = thread->datum;
  1250.     else
  1251.     cond = obj_False;
  1252.  
  1253.     thread_push_escape(thread);
  1254.     set_c_continuation(thread, maybe_return);
  1255.     
  1256.     suspend_other_threads(thread);
  1257.     
  1258.     *thread->sp++ = debugger_restart_var->value;
  1259.     *thread->sp++ = cond;
  1260.     *thread->sp++ = restart;
  1261.     thread_restart(thread);
  1262.     Continue = TRUE;
  1263. }
  1264.  
  1265. static void restart_cmd(void)
  1266. {
  1267.     int tok = yylex();
  1268.  
  1269.     if (tok == tok_EOF)
  1270.     describe_restarts();
  1271.     else if (tok != tok_LITERAL || !obj_is_fixnum(yylval))
  1272.     printf("Bogus restart number, should be an integer.\n");
  1273.     else {
  1274.     int restart = fixnum_value(yylval);
  1275.  
  1276.     if (restart < 0)
  1277.         printf("Bogus restart number, should be >= 0.\n");
  1278.     else
  1279.         do_restart(yylval);
  1280.     }
  1281. }
  1282.  
  1283. static void return_cmd(void)
  1284. {
  1285.     obj_t cond;
  1286.     struct thread *thread;
  1287.  
  1288.     if (debugger_return_var == NULL
  1289.       || debugger_return_var->value == obj_Unbound) {
  1290.     printf("debugger-return undefined.\n");
  1291.     return;
  1292.     }
  1293.  
  1294.     if ((thread = CurThread) == NULL) {
  1295.     printf("No current thread.\n");
  1296.     return;
  1297.     }
  1298.  
  1299.     if (thread->status == status_Debuggered)
  1300.     cond = thread->datum;
  1301.     else {
  1302.     printf("The current thread did not call invoke-debugger\n");
  1303.     return;
  1304.     }
  1305.  
  1306.     *thread->sp++ = obj_True;
  1307.  
  1308.     thread_push_escape(thread);
  1309.     set_c_continuation(thread, maybe_return);
  1310.     
  1311.     suspend_other_threads(thread);
  1312.     
  1313.     *thread->sp++ = debugger_return_var->value;
  1314.     *thread->sp++ = cond;
  1315.     thread_restart(thread);
  1316.     Continue = TRUE;
  1317. }
  1318.     
  1319.  
  1320. /* Thread commands. */
  1321.  
  1322. static struct thread *find_thread(void)
  1323. {
  1324.     int id;
  1325.     struct thread_list *threads;
  1326.  
  1327.     if (instancep(yylval, obj_IntegerClass))
  1328.     id = fixnum_value(yylval);
  1329.     else
  1330.     id = -1;
  1331.  
  1332.     for (threads = all_threads(); threads != NULL; threads = threads->next) {
  1333.     struct thread *thread = threads->thread;
  1334.     if (THREAD(thread->thread_obj)->debug_name == yylval
  1335.           || thread->id == id)
  1336.         return thread;
  1337.     }
  1338.  
  1339.     printf("No thread named ");
  1340.     print(yylval);
  1341.     return NULL;
  1342. }
  1343.     
  1344.  
  1345. static void thread_cmd(void)
  1346. {
  1347.     struct thread_list *threads;
  1348.     struct thread *thread;
  1349.  
  1350.     switch (yylex()) {
  1351.       case tok_EOF:
  1352.     for (threads=all_threads(); threads != NULL; threads=threads->next) {
  1353.         if (threads->thread == CurThread)
  1354.         printf("c ");
  1355.         else
  1356.         printf("  ");
  1357.         print_thread(threads->thread);
  1358.     }
  1359.     break;
  1360.  
  1361.       case tok_SYMBOL:
  1362.       case tok_LITERAL:
  1363.     thread = find_thread();
  1364.     if (thread != NULL)
  1365.         set_thread(thread);
  1366.     break;
  1367.  
  1368.       default:
  1369.     printf("Bogus thread identifier: ");
  1370.     print(yylval);
  1371.     printf("should be either a symbol or integer.");
  1372.     break;
  1373.     }
  1374. }
  1375.  
  1376. static void kill_cmd(void)
  1377. {
  1378.     struct thread *thread;
  1379.  
  1380.     switch (yylex()) {
  1381.       case tok_EOF:
  1382.     thread = CurThread;
  1383.     if (thread == NULL) {
  1384.         printf("No current thread selected.\n");
  1385.         return;
  1386.     }
  1387.     break;
  1388.  
  1389.       case tok_SYMBOL:
  1390.       case tok_LITERAL:
  1391.     thread = find_thread();
  1392.     if (thread == NULL)
  1393.         return;
  1394.     break;
  1395.  
  1396.       default:
  1397.     printf("Bogus thread identifier: ");
  1398.     print(yylval);
  1399.     printf("should be either a symbol or integer.");
  1400.     return;
  1401.     }
  1402.  
  1403.     thread_kill(thread);
  1404.     if (thread == CurThread) {
  1405.     printf("killed the current thread, hence it is no longer current.\n");
  1406.     set_thread(NULL);
  1407.     ThreadChanged = FALSE;
  1408.     FrameChanged = FALSE;
  1409.     }
  1410. }
  1411.     
  1412. static void disable_cmd(void)
  1413. {
  1414.     struct thread *thread;
  1415.  
  1416.     switch (yylex()) {
  1417.       case tok_EOF:
  1418.     thread = CurThread;
  1419.     if (thread == NULL) {
  1420.         printf("No current thread selected.\n");
  1421.         return;
  1422.     }
  1423.     break;
  1424.  
  1425.       case tok_SYMBOL:
  1426.       case tok_LITERAL:
  1427.     thread = find_thread();
  1428.     if (thread == NULL)
  1429.         return;
  1430.     break;
  1431.  
  1432.       default:
  1433.     printf("Bogus thread identifier: ");
  1434.     print(yylval);
  1435.     printf("should be either a symbol or integer.");
  1436.     return;
  1437.     }
  1438.  
  1439.     thread_suspend(thread);
  1440.     print_thread(thread);
  1441. }
  1442.     
  1443. static void enable_cmd(void)
  1444. {
  1445.     struct thread *thread;
  1446.  
  1447.     switch (yylex()) {
  1448.       case tok_EOF:
  1449.     thread = CurThread;
  1450.     if (thread == NULL) {
  1451.         printf("No current thread selected.\n");
  1452.         return;
  1453.     }
  1454.     break;
  1455.  
  1456.       case tok_SYMBOL:
  1457.       case tok_LITERAL:
  1458.     thread = find_thread();
  1459.     if (thread == NULL)
  1460.         return;
  1461.     break;
  1462.  
  1463.       default:
  1464.     printf("Bogus thread identifier: ");
  1465.     print(yylval);
  1466.     printf("should be either a symbol or integer.");
  1467.     return;
  1468.     }
  1469.  
  1470.     if (thread->suspend_count == 0) {
  1471.     printf("thread ");
  1472.     prin1(yylval);
  1473.     printf(" isn't suspended\n");
  1474.     return;
  1475.     }
  1476.  
  1477.     while (thread->suspend_count > 0)
  1478.     thread_restart(thread);
  1479.     print_thread(thread);
  1480. }
  1481.     
  1482.  
  1483. /* Step/next commands */
  1484.  
  1485. static void step_cmd(void)
  1486. {
  1487.     struct thread *thread = CurThread;
  1488.  
  1489.     if (thread == NULL) {
  1490.     printf("No current thread.\n");
  1491.     return;
  1492.     }
  1493.  
  1494.     switch (thread->status) {
  1495.       case status_Running:
  1496.     {
  1497.         enum pause_reason reason;
  1498.         int prev_line = PrevLine;
  1499.  
  1500.         do {
  1501.         reason = single_step(thread);
  1502.         explain_reason(reason);
  1503.         } while (reason == pause_NoReason && CurThread == thread
  1504.              && !FrameChanged && TopFrame->line == prev_line);
  1505.     }
  1506.     break;
  1507.  
  1508.       case status_Debuggered:
  1509.     if (debugger_return_var == NULL
  1510.         || debugger_return_var->value == obj_Unbound) {
  1511.         printf("debugger-return undefined.\n");
  1512.         return;
  1513.     }
  1514.     else {
  1515.         obj_t cond = thread->datum;
  1516.  
  1517.         *thread->sp++ = obj_False;
  1518.  
  1519.         thread_push_escape(thread);
  1520.         set_c_continuation(thread, maybe_return);
  1521.     
  1522.         suspend_other_threads(thread);
  1523.     
  1524.         *thread->sp++ = debugger_return_var->value;
  1525.         *thread->sp++ = cond;
  1526.         thread_restart(thread);
  1527.         Continue = TRUE;
  1528.     }
  1529.  
  1530.     break;
  1531.  
  1532.       default:
  1533.     printf("The current thread is not runnable.\n");
  1534.     return;
  1535.     }
  1536. }
  1537.  
  1538.  
  1539. /* Breakpoint commands */
  1540.  
  1541. static int find_pc_for_line(obj_t component, int line)
  1542. {
  1543.     obj_t debug_info = COMPONENT(component)->debug_info;
  1544.     int len = SOVEC(debug_info)->length;
  1545.     int n_const = COMPONENT(component)->n_constants;
  1546.     int pc = (char *)(&COMPONENT(component)->constant[n_const])
  1547.     - (char *)component;
  1548.     boolean prev_line_before = FALSE;
  1549.     int i;
  1550.     
  1551.     for (i = 0; i < len; i++) {
  1552.     obj_t entry = SOVEC(debug_info)->contents[i];
  1553.     int this_line = fixnum_value(SOVEC(entry)->contents[0]);
  1554.     if (prev_line_before ? line <= this_line : line == this_line)
  1555.         return pc;
  1556.     pc += fixnum_value(SOVEC(entry)->contents[1]);
  1557.     prev_line_before = (this_line != 0 && this_line < line);
  1558.     }
  1559.  
  1560.     return -1;
  1561. }
  1562.  
  1563. static void install_breakpoint(obj_t func, obj_t thing, int line)
  1564. {
  1565.     if (instancep(thing, obj_ComponentClass)) {
  1566.     if (line == -1)
  1567.         printf("Can't install function-start breakpoints directly into "
  1568.            "components.\n");
  1569.     else if (COMPONENT(thing)->debug_info == obj_False) {
  1570.         prin1(func);
  1571.         printf(" has no debug-info.\n");
  1572.     }
  1573.     else {
  1574.         int pc = find_pc_for_line(thing, line);
  1575.  
  1576.         if (pc == -1) {
  1577.         prin1(func);
  1578.         printf(" does not span line number %d\n", line);
  1579.         }
  1580.         else {
  1581.         int id = install_byte_breakpoint(thing, pc);
  1582.         
  1583.         if (id < 0)
  1584.             printf("couldn't install breakpoint in ");
  1585.         else
  1586.             printf("breakpoint %d installed in ", id);
  1587.         prin1(func);
  1588.         printf(" at line %d (pc %d)\n", line, pc);
  1589.         }
  1590.     }
  1591.     }
  1592.     else if (instancep(thing, obj_MethodInfoClass))
  1593.     install_breakpoint(thing, METHOD_INFO(thing)->component, line);
  1594.     else if (!instancep(thing, obj_FunctionClass)) {
  1595.     prin1(thing);
  1596.     printf(" isn't a function, method-info, or component\n");
  1597.     }
  1598.     else if (line == -1) {
  1599.     printf("Can't install function start breakpoints.\n"); /* ### */
  1600.     }
  1601.     else if (!instancep(thing, obj_ByteMethodClass)) {
  1602.     prin1(thing);
  1603.     printf(" isn't a byte method.\n");
  1604.     }
  1605.     else
  1606.     install_breakpoint(func, byte_method_component(thing), line);
  1607. }
  1608.  
  1609. static void breakpoint_cont(struct thread *thread, obj_t *vals)
  1610. {
  1611.     obj_t *old_sp;
  1612.     obj_t okay = vals[0];
  1613.     int line = fixnum_value(thread->fp[0]);
  1614.  
  1615.     if (okay != obj_False) {
  1616.     obj_t results = vals[1];
  1617.     obj_t thing = obj_False;
  1618.  
  1619.     if (SOVEC(results)->length != 0)
  1620.         thing = SOVEC(results)->contents[0];
  1621.  
  1622.     install_breakpoint(thing, thing, line);
  1623.     }
  1624.     old_sp = pop_linkage(thread);
  1625.     do_return(thread, old_sp, old_sp);
  1626. }
  1627.  
  1628. static void breakpoint_cmd(void)
  1629. {
  1630.     obj_t exprs = parse_exprs();
  1631.     
  1632.     if (exprs == obj_False)
  1633.     printf("Invalid function expression.\n");
  1634.     else if (exprs == obj_Nil)
  1635.     list_breakpoints();
  1636.     else {
  1637.     boolean okay = TRUE;
  1638.     boolean func_simple = TRUE;
  1639.     obj_t line;
  1640.  
  1641.     eval_vars(HEAD(exprs), &okay, &func_simple);
  1642.  
  1643.     if (!okay)
  1644.         return;
  1645.  
  1646.     if (TAIL(exprs) == obj_Nil)
  1647.         line = make_fixnum(-1);
  1648.     else if (TAIL(TAIL(exprs)) == obj_Nil) {
  1649.         boolean line_simple = TRUE;
  1650.  
  1651.         eval_vars(HEAD(TAIL(exprs)), &okay, &line_simple);
  1652.  
  1653.         if (!okay)
  1654.         return;
  1655.  
  1656.         line = TAIL(HEAD(TAIL(exprs)));
  1657.         if (!line_simple || !obj_is_fixnum(line)) {
  1658.         printf("Bogus line number.\n");
  1659.         return;
  1660.         }
  1661.     }
  1662.     else {
  1663.         printf("Too many arguments to breakpoint.\n");
  1664.         return;
  1665.     }
  1666.  
  1667.     if (func_simple) {
  1668.         obj_t func = TAIL(HEAD(exprs));
  1669.         install_breakpoint(func, func, fixnum_value(line));
  1670.     }
  1671.     else if (debugger_eval_var == NULL
  1672.          || debugger_eval_var->value == obj_Unbound)
  1673.         printf("Can't eval expressions without debugger-eval "
  1674.            "being defined.\n");
  1675.     else {
  1676.         struct thread *thread = CurThread;
  1677.  
  1678.         if (thread == NULL) {
  1679.         thread = thread_create(make_string("eval for disassemble"));
  1680.         set_c_continuation(thread, kill_me);
  1681.         }
  1682.         else {
  1683.         thread_push_escape(thread);
  1684.         set_c_continuation(thread, debugger_cmd_finished);
  1685.         }
  1686.  
  1687.         suspend_other_threads(thread);
  1688.  
  1689.         *thread->sp++ = obj_False;
  1690.         push_linkage(thread, thread->sp);
  1691.         set_c_continuation(thread, breakpoint_cont);
  1692.         *thread->sp++ = line;
  1693.         thread->datum = obj_rawptr(thread->sp);
  1694.         *thread->sp++ = debugger_eval_var->value;
  1695.         *thread->sp++ = HEAD(exprs);
  1696.  
  1697.         thread_restart(thread);
  1698.  
  1699.         Continue = TRUE;
  1700.     }
  1701.     }
  1702. }
  1703.  
  1704. static void delete_cmd(void)
  1705. {
  1706.     if (yylex() != tok_LITERAL || !obj_is_fixnum(yylval))
  1707.     printf("Bogus breakpoint id\n");
  1708.     else
  1709.     remove_breakpoint(fixnum_value(yylval));
  1710. }
  1711.  
  1712.  
  1713. /* Disassemble command */
  1714.  
  1715. static struct byteop_info {
  1716.     int match;
  1717.     int mask;
  1718.     char *op;
  1719. } ByteOpInfos[] = {
  1720.     {op_TRAP, 0xff, "trap"},
  1721.     {op_BREAKPOINT, 0xff, "breakpoint"},
  1722.     {op_RETURN_SINGLE, 0xff, "return single"},
  1723.     {op_MAKE_VALUE_CELL, 0xff, "make-value-cell"},
  1724.     {op_VALUE_CELL_REF, 0xff, "value-cell-ref"},
  1725.     {op_VALUE_CELL_SET, 0xff, "value-cell-set"},
  1726.     {op_MAKE_METHOD, 0xff, "make-method"},
  1727.     {op_CHECK_TYPE, 0xff, "check-type"},
  1728.     {op_CHECK_TYPE_FUNCTION, 0xff, "check-type-function"},
  1729.     {op_CANONICALIZE_VALUE, 0xff, "canonicalize-value %r"},
  1730.     {op_PUSH_BYTE, 0xff, "push\t%b"},
  1731.     {op_PUSH_INT, 0xff, "push\t%i"},
  1732.     {op_CONDITIONAL_BRANCH, 0xff, "cbr\t%t"},
  1733.     {op_BRANCH, 0xff, "br\t%t"},
  1734.     {op_PUSH_NIL, 0xff, "push\t#()"},
  1735.     {op_PUSH_UNBOUND, 0xff, "push\t#unbound"},
  1736.     {op_PUSH_TRUE, 0xff, "push\t#t"},
  1737.     {op_PUSH_FALSE, 0xff, "push\t#f"},
  1738.     {op_DUP, 0xff, "dup"},
  1739.     {op_DOT_TAIL, 0xff, "dot\ttail"},
  1740.     {op_DOT_FOR_MANY, 0xff, "dot\tfor %r"},
  1741.     {op_DOT_FOR_SINGLE, 0xff, "dot\tfor single"},
  1742.  
  1743.     {op_PUSH_CONSTANT, 0xf0, "push\tconst(%c)\t"},
  1744.     {op_PUSH_ARG, 0xf0, "push\targ(%a)"},
  1745.     {op_POP_ARG, 0xf0, "pop\targ(%a)"},
  1746.     {op_PUSH_LOCAL, 0xf0, "push\tlocal(%a)"},
  1747.     {op_POP_LOCAL, 0xf0, "pop\tlocal(%a)"},
  1748.     {op_CALL_TAIL, 0xf0, "call\tnargs = %a, tail"},
  1749.     {op_CALL_FOR_MANY, 0xf0, "call\tnargs = %n, for %r"},
  1750.     {op_CALL_FOR_SINGLE, 0xf0, "call\tnargs = %n, for single"},
  1751.     {op_PUSH_VALUE, 0xf0, "push\tvalue %v"},
  1752.     {op_PUSH_FUNCTION, 0xf0, "push\tfunction %v"},
  1753.     {op_POP_VALUE, 0xf0, "pop\tvalue %v"},
  1754.  
  1755.     {op_PLUS, 0xff, "+"},
  1756.     {op_MINUS, 0xff, "-"},
  1757.     {op_LT, 0xff, "<"},
  1758.     {op_LE, 0xff, "<="},
  1759.     {op_EQ, 0xff, "="},
  1760.     {op_IDP, 0xff, "=="},
  1761.     {op_NE, 0xff, "~="},
  1762.     {op_GE, 0xff, ">="},
  1763.     {op_GT, 0xff, ">"},
  1764.     {0, 0, NULL}
  1765. };
  1766.  
  1767. static int disassem_int4(unsigned char *ptr)
  1768. {
  1769.     return ptr[0] | (ptr[1] << 8) | (ptr[2] << 16) | (ptr[3] << 24);
  1770. }
  1771.  
  1772. static unsigned char *disassemble_op(obj_t component, unsigned char *start)
  1773. {
  1774.     unsigned char *ptr = start;
  1775.     unsigned char byte = *ptr++;
  1776.     struct byteop_info *info;
  1777.     char buf[256], *fill = buf, *msg = "";
  1778.     int i, c;
  1779.     obj_t trailer = NULL;
  1780.     boolean extra = FALSE;
  1781.  
  1782.     for (info = ByteOpInfos; info->op != NULL; info++)
  1783.     if ((info->mask & byte) == info->match) {
  1784.         msg = info->op;
  1785.         break;
  1786.     }
  1787.  
  1788.     do {
  1789.     c = *msg++;
  1790.     if (c == '%') {
  1791.         switch (*msg++) {
  1792.           case 'a':
  1793.         i = byte & 0xf;
  1794.         if (i == 0xf) {
  1795.             i = *ptr++;
  1796.             if (i == 0xff) {
  1797.             i = disassem_int4(ptr);
  1798.             ptr += 4;
  1799.             }
  1800.         }
  1801.         sprintf(fill, "%d", i);
  1802.         break;
  1803.  
  1804.           case 'b':
  1805.         sprintf(fill, "%d", *(signed char *)(ptr++));
  1806.         break;
  1807.  
  1808.           case 'c':
  1809.         i = byte & 0xf;
  1810.         if (i == 0xf) {
  1811.             i = *ptr++;
  1812.             if (i == 0xff) {
  1813.             i = disassem_int4(ptr);
  1814.             ptr += 4;
  1815.             }
  1816.         }
  1817.         sprintf(fill, "%d", i);
  1818.         trailer = COMPONENT(component)->constant[i];
  1819.         break;
  1820.  
  1821.           case 'i':
  1822.         sprintf(fill, "%d", disassem_int4(ptr));
  1823.         ptr += 4;
  1824.         break;
  1825.  
  1826.           case 'n':
  1827.         i = byte & 0xf;
  1828.         if (i == 0xf) {
  1829.             extra = TRUE;
  1830.             i = *ptr++;
  1831.             if (i == 0xff) {
  1832.             i = disassem_int4(ptr);
  1833.             ptr += 4;
  1834.             }
  1835.         }
  1836.         sprintf(fill, "%d", i);
  1837.         break;
  1838.  
  1839.           case 'r':
  1840.         i = *ptr++;
  1841.         if (i == 0xff) {
  1842.             i = disassem_int4(ptr);
  1843.             ptr += 4;
  1844.         }
  1845.         sprintf(fill, "%d", i>>1);
  1846.         if (i & 1)
  1847.             strcat(fill, ", #rest");
  1848.         break;
  1849.  
  1850.           case 't':
  1851.         ptr += 4;
  1852.         sprintf(fill, "%d",
  1853.             (int) (ptr - (unsigned char *)component
  1854.                    + disassem_int4(ptr-4)));
  1855.         break;
  1856.  
  1857.           case 'v':
  1858.         i = byte & 0xf;
  1859.         if (i == 0xf) {
  1860.             i = *ptr++;
  1861.             if (i == 0xff) {
  1862.             i = disassem_int4(ptr);
  1863.             ptr += 4;
  1864.             }
  1865.         }
  1866.         trailer = ((struct variable *)COMPONENT(component)
  1867.                ->constant[i])
  1868.             ->name;
  1869.         fill[0] = '\0';
  1870.         break;
  1871.  
  1872.           default:
  1873.         fill[0] = '?';
  1874.         fill[1] = '?';
  1875.         fill[2] = '?';
  1876.         fill[3] = '\0';
  1877.         }
  1878.         fill = strchr(fill, '\0');
  1879.     }
  1880.     else
  1881.         *fill++ = c;
  1882.     } while (c != '\0');
  1883.  
  1884.     if (extra)
  1885.     ptr++;
  1886.  
  1887.     for (i = 0; i < (ptr - start); i++)
  1888.     printf(" %02x", start[i]);
  1889.     while (i++ < 4)
  1890.     printf("   ");
  1891.     printf("\t%s", buf);
  1892.     if (trailer != NULL)
  1893.     prin1(trailer);
  1894.  
  1895.     return ptr;
  1896. }
  1897.  
  1898. static void disassemble_component(obj_t component)
  1899. {
  1900.     obj_t debug_name = COMPONENT(component)->debug_name;
  1901.     obj_t debug_info = COMPONENT(component)->debug_info;
  1902.     obj_t source_file = COMPONENT(component)->source_file;
  1903.     obj_t mtime = COMPONENT(component)->mtime;
  1904.     int nconst = COMPONENT(component)->n_constants;
  1905.     unsigned char *ptr
  1906.     = (unsigned char *)(COMPONENT(component)->constant + nconst);
  1907.     unsigned char *end
  1908.     = obj_ptr(unsigned char *, component) + COMPONENT(component)->length;
  1909.     int debug_index = 0;
  1910.     unsigned char *next_line;
  1911.     int i;
  1912.  
  1913.     if (debug_name == obj_False)
  1914.     printf("anonymous");
  1915.     else
  1916.     prin1(debug_name);
  1917.     printf(" component");
  1918.     if (source_file != obj_False) {
  1919.     printf(", from ");
  1920.     prin1(source_file);
  1921.     }
  1922.  
  1923.     if (debug_info == obj_False)
  1924.     next_line = end;
  1925.     else
  1926.     next_line = ptr;
  1927.  
  1928.     while (ptr < end) {
  1929.     while (ptr >= next_line) {
  1930.         obj_t entry = SOVEC(debug_info)->contents[debug_index++];
  1931.         int line = fixnum_value(SOVEC(entry)->contents[0]);
  1932.         if (line != 0) {
  1933.         FILE *source = find_source_line(source_file, mtime, line);
  1934.         if (source) {
  1935.             int c;
  1936.             printf("\n%d\t", line);
  1937.             while ((c = getc(source)) != EOF && c != '\n')
  1938.             putchar(c);
  1939.         }
  1940.         else
  1941.             printf("\nline %d:", line);
  1942.         }
  1943.         next_line += fixnum_value(SOVEC(entry)->contents[1]);
  1944.     }
  1945.     printf("\n%6d:", (int)(ptr - (unsigned char *)component));
  1946.     ptr = disassemble_op(component, ptr);
  1947.     }
  1948.     putchar('\n');
  1949.  
  1950.     for (i = 0; i < nconst; i++) {
  1951.     obj_t c = COMPONENT(component)->constant[i];
  1952.     if (instancep(c, obj_MethodInfoClass)) {
  1953.         putchar('\n');
  1954.         prin1(c);
  1955.         printf(", ");
  1956.         disassemble_component(METHOD_INFO(c)->component);
  1957.     }
  1958.     }
  1959. }
  1960.  
  1961. static void disassemble_thing(obj_t thing)
  1962. {
  1963.     if (instancep(thing, obj_ComponentClass))
  1964.     disassemble_component(thing);
  1965.     else if (instancep(thing, obj_ByteMethodClass))
  1966.     disassemble_component(byte_method_component(thing));
  1967.     else if (instancep(thing, obj_FunctionClass)) {
  1968.     printf("don't know how to disassemble ");
  1969.     print(thing);
  1970.     }
  1971.     else {
  1972.     prin1(thing);
  1973.     printf(" isn't a function or component\n");
  1974.     }
  1975. }
  1976.  
  1977. static void disassemble_cont(struct thread *thread, obj_t *vals)
  1978. {
  1979.     obj_t *old_sp;
  1980.     obj_t okay = vals[0];
  1981.  
  1982.     if (okay != obj_False) {
  1983.     obj_t results = vals[1];
  1984.     if (SOVEC(results)->length == 0)
  1985.         disassemble_thing(obj_False);
  1986.     else
  1987.         disassemble_thing(SOVEC(results)->contents[0]);
  1988.     }
  1989.     old_sp = pop_linkage(thread);
  1990.     do_return(thread, old_sp, old_sp);
  1991. }
  1992.  
  1993. static void disassemble_cmd(void)
  1994. {
  1995.     obj_t exprs = parse_exprs();
  1996.  
  1997.     if (exprs == obj_False)
  1998.     printf("Invalid function expression.\n");
  1999.     else if (exprs == obj_Nil) {
  2000.     if (CurFrame == NULL)
  2001.         printf("No current frame.\n");
  2002.     else if (obj_is_fixnum(CurFrame->component))
  2003.         printf("Current frame is not in a byte method\n");
  2004.     else
  2005.         disassemble_component(CurFrame->component);
  2006.     }
  2007.     else if (TAIL(exprs) != obj_Nil)
  2008.     printf("Too many expressions for disassemble\n");
  2009.     else {
  2010.     boolean okay = TRUE;
  2011.     boolean simple = TRUE;
  2012.  
  2013.     eval_vars(HEAD(exprs), &okay, &simple);
  2014.  
  2015.     if (!okay)
  2016.         return;
  2017.  
  2018.     if (simple)
  2019.         disassemble_thing(TAIL(HEAD(exprs)));
  2020.     else if (debugger_eval_var == NULL
  2021.          || debugger_eval_var->value == obj_Unbound)
  2022.         printf("Can't eval expressions without debugger-eval "
  2023.            "being defined.\n");
  2024.     else {
  2025.         struct thread *thread = CurThread;
  2026.  
  2027.         if (thread == NULL) {
  2028.         thread = thread_create(make_string("eval for disassemble"));
  2029.         set_c_continuation(thread, kill_me);
  2030.         }
  2031.         else {
  2032.         thread_push_escape(thread);
  2033.         set_c_continuation(thread, debugger_cmd_finished);
  2034.         }
  2035.  
  2036.         suspend_other_threads(thread);
  2037.  
  2038.         *thread->sp++ = obj_False;
  2039.         push_linkage(thread, thread->sp);
  2040.         set_c_continuation(thread, disassemble_cont);
  2041.         thread->datum = obj_rawptr(thread->sp);
  2042.         *thread->sp++ = debugger_eval_var->value;
  2043.         *thread->sp++ = HEAD(exprs);
  2044.  
  2045.         thread_restart(thread);
  2046.  
  2047.         Continue = TRUE;
  2048.     }
  2049.     }
  2050. }
  2051.  
  2052.  
  2053. /* Describe command. */
  2054.  
  2055. static void describe_cont(struct thread *thread, obj_t *vals)
  2056. {
  2057.     obj_t *old_sp;
  2058.     obj_t okay = vals[0];
  2059.  
  2060.     if (okay != obj_False) {
  2061.     obj_t results = vals[1];
  2062.     if (SOVEC(results)->length == 0)
  2063.         describe(obj_False);
  2064.     else
  2065.         describe(SOVEC(results)->contents[0]);
  2066.     }
  2067.     old_sp = pop_linkage(thread);
  2068.     do_return(thread, old_sp, old_sp);
  2069. }
  2070.  
  2071. static void describe_cmd(void)
  2072. {
  2073.     obj_t exprs = parse_exprs();
  2074.  
  2075.     if (exprs == obj_False)
  2076.     printf("Invalid expression.\n");
  2077.     else if (exprs == obj_Nil)
  2078.     printf("Describe what?\n");
  2079.     else if (TAIL(exprs) != obj_Nil)
  2080.     printf("too many things to describe, one at most.\n");
  2081.     else {
  2082.     boolean okay = TRUE;
  2083.     boolean simple = TRUE;
  2084.  
  2085.     eval_vars(HEAD(exprs), &okay, &simple);
  2086.  
  2087.     if (!okay)
  2088.         return;
  2089.  
  2090.     if (simple)
  2091.         describe(TAIL(HEAD(exprs)));
  2092.     else if (debugger_eval_var == NULL
  2093.          || debugger_eval_var->value == obj_Unbound)
  2094.         printf("Can't eval expressions without debugger-eval "
  2095.            "being defined.\n");
  2096.     else {
  2097.         struct thread *thread = CurThread;
  2098.  
  2099.         if (thread == NULL) {
  2100.         thread = thread_create(make_string("eval for disassemble"));
  2101.         set_c_continuation(thread, kill_me);
  2102.         }
  2103.         else {
  2104.         thread_push_escape(thread);
  2105.         set_c_continuation(thread, debugger_cmd_finished);
  2106.         }
  2107.  
  2108.         suspend_other_threads(thread);
  2109.  
  2110.         *thread->sp++ = obj_False;
  2111.         push_linkage(thread, thread->sp);
  2112.         set_c_continuation(thread, describe_cont);
  2113.         thread->datum = obj_rawptr(thread->sp);
  2114.         *thread->sp++ = debugger_eval_var->value;
  2115.         *thread->sp++ = HEAD(exprs);
  2116.  
  2117.         thread_restart(thread);
  2118.  
  2119.         Continue = TRUE;
  2120.     }
  2121.     }
  2122. }
  2123.  
  2124.  
  2125.  
  2126. /* Command table. */
  2127.  
  2128. static struct cmd_entry Cmds[] = {
  2129.     {"abort", "abort\t\tInvoke the first available <abort> restart.",
  2130.      abort_cmd},
  2131.     {"backtrace",
  2132.      "backtrace\tDisplay a stack backtrace for the current thread.",
  2133.      backtrace_cmd},
  2134.     {"breakpoint", "breakpoint\tInstall a breakpoint.", breakpoint_cmd},
  2135.     {"c", NULL, continue_cmd},
  2136.     {"call", "call expr...\tCall each expr, printing the results.", call_cmd},
  2137.     {"continue", "continue\tContinue execution.", continue_cmd},
  2138.     {"d", NULL, down_cmd},
  2139.     {"delete", "delete id\tDelete the given breakpoint.", delete_cmd},
  2140.     {"describe", "describe inst\tDescribe the slots instance.", describe_cmd},
  2141.     {"disable", "disable thread\tSuspend the given thread.", disable_cmd},
  2142.     {"disassemble",
  2143.      "disassemble\tDisassemble the component for the current frame",
  2144.      disassemble_cmd},
  2145.     {"down", "down\t\tMove down one frame.", down_cmd},
  2146.     {"enable", "enable thread\tRestart the given thread.", enable_cmd},
  2147.     {"error",
  2148. "error\t\tRedisplay the error that caused this thread to enter the debugger.",
  2149.      error_cmd},
  2150.     {"flush", "flush\t\tFlush all debugger variables.", flush_cmd},
  2151.     {"frame", "frame [num]\tMove to the given frame.", frame_cmd},
  2152.     {"gc", "gc\t\tCollect garbage.", gc_cmd},
  2153.     {"help", "help [topic]\tDisplay help about some topic.", help_cmd},
  2154.     {"kill", "kill thread\tKill the given thread.", kill_cmd},
  2155.     {"l", NULL, locals_cmd},
  2156.     {"library",
  2157.      "library [lib]\tSwitch to given library or list all libraries.",
  2158.      library_cmd},
  2159.     {"locals", "locals\t\tDisplay all the locals in the current frame.",
  2160.      locals_cmd},
  2161.     {"module",
  2162.  "module [module]\tSwitch to given module or list modules in current library.",
  2163.      module_cmd},
  2164.     {"print", "print expr...\tPrint each expr, ignoring errors.", print_cmd},
  2165.     {"restart", "restart [num]\tList or invoke one of the available restarts.",
  2166.      restart_cmd},
  2167.     {"return",
  2168.      "return\t\tReturn from this call to invoke-debugger (if allowed)",
  2169.      return_cmd},
  2170.     {"step", "step\t\tStep the current thread one byte-op.", step_cmd},
  2171.     {"thread", "thread [name]\tSwitch to given thread or list all threads.",
  2172.      thread_cmd},
  2173.     {"troff", "troff\t\tTurn function/return tracing off.", troff_cmd},
  2174.     {"tron", "tron\t\tTurn function/return tracing on.", tron_cmd},
  2175.     {"up", "up\t\tMove up one frame.", up_cmd},
  2176.     {"quit", "quit\t\tQuit.", quit_cmd},
  2177.     {NULL, NULL, NULL}
  2178. };
  2179.     
  2180. static void do_cmd(void)
  2181. {
  2182.     struct cmd_entry *entry = find_cmd(Cmds, "command");
  2183.  
  2184.     if (entry)
  2185.     (*entry->fn)();
  2186. }
  2187.  
  2188. static void help_cmd(void)
  2189. {
  2190.     struct cmd_entry *ptr;
  2191.  
  2192.     for (ptr = Cmds; ptr->cmd != NULL; ptr++)
  2193.     if (ptr->help)
  2194.         printf("%s\n", ptr->help);
  2195. }
  2196.  
  2197.  
  2198. /* The main debugger loop */
  2199.  
  2200. static void maybe_print_frame(void)
  2201. {
  2202.     if (ThreadChanged) {
  2203.     ThreadChanged = FALSE;
  2204.  
  2205.     if (CurThread == NULL) {
  2206.         printf("no current thread\n");
  2207.         FrameChanged = FALSE;
  2208.     }
  2209.     else {
  2210.         printf("thread ");
  2211.         print_thread(CurThread);
  2212.         FrameChanged = TRUE;
  2213.     }
  2214.     }
  2215.  
  2216.     if (FrameChanged) {
  2217.     if (CurFrame == NULL)
  2218.         printf("No stack.\n");
  2219.     else
  2220.         print_frame(CurFrame, FALSE);
  2221.     FrameChanged = FALSE;
  2222.     PrevLine = -1;
  2223.     }
  2224.  
  2225.     if (CurFrame != NULL
  2226.       && CurFrame->source_file != obj_False
  2227.       && CurFrame->line != PrevLine) {
  2228.     printf("%s", string_chars(CurFrame->source_file));
  2229.     if (CurFrame->line != 0) {
  2230.         int line = CurFrame->line;
  2231.         FILE *source = find_source_line(CurFrame->source_file,
  2232.                         CurFrame->mtime,
  2233.                         line);
  2234.         if (source) {
  2235.         int c;
  2236.         printf("\n%d\t", line);
  2237.         while ((c = getc(source)) != EOF && c <= ' ')
  2238.             ;
  2239.         while (c != EOF && c != '\n') {
  2240.             putchar(c);
  2241.             c = getc(source);
  2242.         }
  2243.         putchar('\n');
  2244.         }
  2245.         else
  2246.         printf(", line %d.\n", line);
  2247.     }
  2248.     else
  2249.         putchar('\n');
  2250.     PrevLine = CurFrame->line;
  2251.     }
  2252. }
  2253.  
  2254. static void blow_off_cmd(void)
  2255. {
  2256.     longjmp(BlowOffCmd, TRUE);
  2257. }
  2258.  
  2259. void invoke_debugger(enum pause_reason reason)
  2260. {
  2261.     char line[256];
  2262.  
  2263.     Continue = FALSE;
  2264.  
  2265.     explain_reason(reason);
  2266.  
  2267.     while (Continue) {
  2268.     Continue = FALSE;
  2269.     reason = do_stuff();
  2270.     explain_reason(reason);
  2271.     }
  2272.  
  2273.     if (!isatty(fileno(stdin))) {
  2274.     printf("STDIN is not a tty.  Cannot debug.\n");
  2275.     exit(1);
  2276.     }
  2277.  
  2278.     lex_init();
  2279.  
  2280.     while (1) {
  2281.     thread_set_current(NULL);
  2282.  
  2283.     while (!Continue) {
  2284.  
  2285.         maybe_print_frame();
  2286.  
  2287.         if (setjmp(BlowOffCmd))
  2288.         printf("\ninterrupted\n");
  2289.         else
  2290.         set_interrupt_handler(blow_off_cmd);
  2291.  
  2292.         printf("mindy> ");
  2293.         fflush(stdout);
  2294.  
  2295.         if (fgets(line, sizeof(line), stdin) == NULL) {
  2296.         putchar('\n');
  2297.         lex_setup("quit", 4);
  2298.         }
  2299.         else
  2300.         lex_setup(line, strlen(line));
  2301.  
  2302.         clear_interrupt_handler();
  2303.  
  2304.         switch (yylex()) {
  2305.           case tok_EOF:
  2306.         break;
  2307.           case tok_SYMBOL:
  2308.         do_cmd();
  2309.         break;
  2310.           default:
  2311.         printf("Bogus command -- use ``help'' for help.\n");
  2312.         break;
  2313.         }
  2314.     }
  2315.     Continue = FALSE;
  2316.  
  2317.     reason = do_stuff();
  2318.     explain_reason(reason);
  2319.     }
  2320. }
  2321.  
  2322.  
  2323. /* GC stuff. */
  2324.  
  2325. void scavenge_debug_roots(void)
  2326. {
  2327.     scavenge(&do_print_func);
  2328.     scavenge(&do_eval_func);
  2329.     scavenge(&cur_source_file);
  2330.     scav_frames(TopFrame);
  2331.     if (CurThreadObj)
  2332.     scavenge(&CurThreadObj);
  2333. }
  2334.  
  2335.  
  2336. /* Initialization stuff. */
  2337.  
  2338. void init_debug_functions(void)
  2339. {
  2340.     cur_source_file = obj_False;
  2341.     do_print_func = make_raw_function("debug-print", 1, FALSE, obj_False,
  2342.                       FALSE, obj_Nil, obj_ObjectClass,
  2343.                       do_print_start);
  2344.     do_eval_func = make_raw_function("debug-eval", 1, FALSE, obj_False,
  2345.                      FALSE, obj_Nil, obj_ObjectClass,
  2346.                      do_eval_start);
  2347.     debugger_eval_var = find_variable(module_BuiltinStuff,
  2348.                       symbol("debugger-eval"),
  2349.                       FALSE, TRUE);
  2350.     debugger_flush_var = find_variable(module_BuiltinStuff,
  2351.                       symbol("debugger-flush"),
  2352.                       FALSE, TRUE);
  2353.     debugger_call_var = find_variable(module_BuiltinStuff,
  2354.                       symbol("debugger-call"),
  2355.                       FALSE, TRUE);
  2356.     debugger_print_var = find_variable(module_BuiltinStuff,
  2357.                        symbol("debugger-print"),
  2358.                        FALSE, TRUE);
  2359.     debugger_report_var = find_variable(module_BuiltinStuff,
  2360.                     symbol("debugger-report-condition"),
  2361.                     FALSE, TRUE);
  2362.     debugger_abort_var = find_variable(module_BuiltinStuff,
  2363.                        symbol("debugger-abort"),
  2364.                        FALSE, TRUE);
  2365.     debugger_restarts_var = find_variable(module_BuiltinStuff,
  2366.                       symbol("debugger-describe-restarts"),
  2367.                       FALSE, TRUE);
  2368.     debugger_restart_var = find_variable(module_BuiltinStuff,
  2369.                      symbol("debugger-restart"),
  2370.                      FALSE, TRUE);
  2371.     debugger_return_var = find_variable(module_BuiltinStuff,
  2372.                     symbol("debugger-return"),
  2373.                     FALSE, TRUE);
  2374. }
  2375.